# pythonProject5/api/v1/auth.py

from fastapi import APIRouter, Depends, HTTPException, status, Body, WebSocket
from sqlalchemy.orm import Session
from typing import Dict, Optional
from datetime import timedelta
import logging
from models.db import User
from core.security import get_current_user
from db.session import get_db_session as get_db
from core.security import (
    verify_password,
    create_access_token,
    create_refresh_token,
    hash_password,
    generate_salt,
    decode_token,           # 新增：导入 decode_token
    decode_token_safe,      # 新增：导入安全版本的decode_token
)
from core.config import settings
from schemas.auth import LoginRequest, RegisterRequest, TokenResponse

router = APIRouter(tags=["Authentication"])
logger = logging.getLogger(__name__)

# -------------------- 现有的注册、登录、刷新令牌等部分 --------------------

@router.post("/register", response_model=Dict, status_code=status.HTTP_201_CREATED)
def register(user_in: RegisterRequest, db: Session = Depends(get_db)):
    """用户注册"""
    # 验证邮箱是否已存在
    existing_email = db.query(User).filter(User.email == user_in.email).first()
    if existing_email:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="邮箱已被使用"
        )
    
    # 处理用户名
    import random
    import string
    
    if user_in.username:
        # 用户提供了用户名
        username = user_in.username
    else:
        # 如果用户没有提供用户名，从邮箱生成
        username = user_in.email.split('@')[0]
        # 确保用户名长度符合要求
        if len(username) < 3:
            username = username + "user"  # 确保长度至少为3
        if len(username) > 50:
            username = username[:50]  # 截断过长的用户名
    
    # 检查用户名是否已存在
    existing_username = db.query(User).filter(User.username == username).first()
    if existing_username:
        # 用户名已存在，添加随机后缀
        random_suffix = ''.join(random.choices(string.digits, k=4))
        username = f"{username}{random_suffix}"
        
    # 再次验证用户名长度
    if len(username) < 3:
        username = username + "123"  # 确保长度至少为3
    if len(username) > 50:
        username = username[:50]  # 截断过长的用户名

    # 创建用户
    salt = generate_salt()
    user = User(
        username=username,  # 使用可能已经修改过的用户名
        email=user_in.email,
        salt=salt,
        hashed_password=hash_password(user_in.password, salt),
        is_active=True
    )
    try:
        db.add(user)
        db.commit()
        db.refresh(user)
        logger.info(f"用户注册成功: {user.username}")
        return {"message": "注册成功", "user_id": user.id, "username": user.username}
    except Exception as e:
        db.rollback()
        logger.error(f"用户注册失败: {e}")
        raise HTTPException(status_code=500, detail="注册失败")


@router.post("/login", response_model=TokenResponse)
def login(form_data: LoginRequest, db: Session = Depends(get_db)):
    """用户登录，返回 JWT 令牌"""
    # 支持使用用户名或邮箱登录
    user = None
    if form_data.username:
        user = db.query(User).filter(User.username == form_data.username).first()
    elif form_data.email:
        user = db.query(User).filter(User.email == form_data.email).first()
    else:
        # 这应该由 Pydantic 验证器捕获，但为了安全起见
        raise HTTPException(status_code=400, detail="请提供用户名或邮箱")
    
    if not user:
        raise HTTPException(status_code=400, detail="用户名、邮箱或密码错误")

    if not user.is_active:
        raise HTTPException(status_code=400, detail="账户已被禁用")

    if not verify_password(form_data.password, user.hashed_password, user.salt):
        raise HTTPException(status_code=400, detail="用户名、邮箱或密码错误")

    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": str(user.id)},
        expires_delta=access_token_expires
    )
    refresh_token = create_refresh_token(
        data={"sub": str(user.id)}
    )

    logger.info(f"用户登录成功: {user.username}")
    return {
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer",
        "expires_in": settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        "user": {
            "id": user.id,
            "username": user.username,
            "email": user.email
        }
    }


@router.post("/refresh", response_model=TokenResponse)
def refresh_token(
    refresh_token_str: str = Body(..., embed=True, alias="refresh_token"),
    db: Session = Depends(get_db)
):
    """使用 refresh token 获取新的 access token"""
    payload = decode_token(refresh_token_str)
    if payload is None:
        raise HTTPException(status_code=401, detail="无效或过期的刷新令牌")

    if payload.get("type") != "refresh":
        raise HTTPException(status_code=401, detail="令牌类型错误")

    user_id = payload.get("sub")
    if not user_id:
        raise HTTPException(status_code=401, detail="无效的令牌")

    user = db.query(User).filter(User.id == int(user_id)).first()
    if not user:
        raise HTTPException(status_code=404, detail="用户不存在")

    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    new_access_token = create_access_token(
        data={"sub": str(user.id)},
        expires_delta=access_token_expires
    )
    new_refresh_token = create_refresh_token(
        data={"sub": str(user.id)}
    )

    return {
        "access_token": new_access_token,
        "refresh_token": new_refresh_token,
        "token_type": "bearer",
        "expires_in": settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        "user": {
            "id": user.id,
            "username": user.username,
            "email": user.email
        }
    }


@router.get("/profile")
def get_profile(current_user: User = Depends(get_current_user)):
    """获取当前用户信息"""
    return {
        "id": current_user.id,
        "username": current_user.username,
        "email": current_user.email,
        "is_active": current_user.is_active
    }


# -------------------- 新增：WebSocket 认证函数 --------------------

def get_current_user_from_token_sync(token: str, db: Session) -> User:
    """
    同步版本：从 JWT token 解析用户
    更适合在 WebSocket 中使用
    """
    if not token:
        raise HTTPException(status_code=401, detail="缺少 token")

    # 解析 token 获取用户 ID
    payload = decode_token_safe(token)  # 使用安全版本
    if payload is None:
        raise HTTPException(status_code=401, detail="无效或过期的 token")

    user_id = payload.get("sub")
    if not user_id:
        raise HTTPException(status_code=401, detail="token 中缺少用户 ID")

    user = db.query(User).filter(User.id == int(user_id)).first()
    if not user:
        raise HTTPException(status_code=404, detail="用户不存在")
    if not user.is_active:
        raise HTTPException(status_code=403, detail="账户已被禁用")

    return user


# WebSocket 认证函数
async def get_current_user_ws(token: str, db: Session):
    """WebSocket 认证：解析 WebSocket 连接的 token 并返回当前用户"""
    user = get_current_user_from_token_sync(token, db)
    return {
        "id": user.id,
        "username": user.username,
        "email": user.email
    }
